package com.ytktt.study.week9.task3.rpcfx.client.proxy;

import com.ytktt.study.week9.task3.rpcfx.constant.RpcfxConstant;
import com.ytktt.study.week9.task3.rpcfx.enums.ErrResponseEnum;
import com.ytktt.study.week9.task3.rpcfx.exception.RpcfxException;
import com.ytktt.study.week9.task3.rpcfx.utils.StringFormatUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;

/**
 * ByteBuddy代理
 *
 * @author ytk
 */
@Slf4j
@RequiredArgsConstructor
public class ByteBuddyDynamicProxy implements RpcfxDynamicProxy {

    private final ByteBuddyRpcfxInterceptor interceptor;

    @Override
    public Object create(String serviceName) {
        Class<?> klass;
        try {
            klass = Class.forName(RpcfxConstant.SERVICE_PACKAGE_PREFIX + '.' + StringFormatUtils.upperFirstLetter(serviceName));
        } catch (ClassNotFoundException e) {
            throw new RpcfxException(ErrResponseEnum.UNKNOWN_SERVICE_ERROR);
        }
        try {
            return new ByteBuddy().subclass(Object.class).name(RpcfxConstant.SERVICE_PACKAGE_PREFIX).implement(klass)
                    .method(ElementMatchers.isDeclaredBy(klass))
                    .intercept(MethodDelegation.to(this.interceptor))
                    .make()
                    .load(klass.getClassLoader())
                    .getLoaded()
                    .newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RpcfxException(ErrResponseEnum.UNKNOWN_ERROR);
        }
    }
}
